/*
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Rhino code, released
 * May 6, 1999.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1997-1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Waldemar Horwat
 *   Roger Lawrence
 *   Attila Szegedi
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU General Public License Version 2 or later (the "GPL"), in which
 * case the provisions of the GPL are applicable instead of those above. If
 * you wish to allow use of your version of this file only under the terms of
 * the GPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replacing
 * them with the notice and other provisions required by the GPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the GPL.
 *
 * ***** END LICENSE BLOCK ***** */

/****************************************************************
 *
 * The author of this software is David M. Gay.
 *
 * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose without fee is hereby granted, provided that this entire notice
 * is included in all copies of any software which is or includes a copy
 * or modification of this software and in all copies of the supporting
 * documentation for such software.
 *
 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
 *
 ***************************************************************/
package com.google.javascript.rhino.dtoa;

import com.google.common.annotations.GwtIncompatible;
import java.math.BigInteger;

@GwtIncompatible("unnecessarily complex")
public final class DToA {

  private static final int
      DTOSTR_STANDARD = 0, /* Either fixed or exponential format; round-trip */
      DTOSTR_STANDARD_EXPONENTIAL = 1, /* Always exponential format; round-trip */
      DTOSTR_FIXED =
          2, /* Round to <precision> digits after the decimal point; exponential if number is large */
      DTOSTR_EXPONENTIAL = 3, /* Always exponential format; <precision> significant digits */
      DTOSTR_PRECISION = 4; /* Either fixed or exponential format; <precision> significant digits */

  private static final int Frac_mask = 0xfffff;
  private static final int Exp_shift = 20;
  private static final int Exp_msk1 = 0x100000;

  private static final int Bias = 1023;
  private static final int P = 53;

  private static final int Exp_shift1 = 20;
  private static final int Exp_mask = 0x7ff00000;
  private static final int Bndry_mask = 0xfffff;
  private static final int Log2P = 1;

  private static final int Sign_bit = 0x80000000;
  private static final int Exp_11 = 0x3ff00000;
  private static final int Ten_pmax = 22;
  private static final int Quick_max = 14;
  private static final int Bletch = 0x10;
  private static final int Frac_mask1 = 0xfffff;
  private static final int Int_max = 14;
  private static final int n_bigtens = 5;

  private static final double tens[] = {
    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16,
    1e17, 1e18, 1e19, 1e20, 1e21, 1e22
  };

  private static final double bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256};

  private static int lo0bits(int y) {
    int k;
    int x = y;

    if ((x & 7) != 0) {
      if ((x & 1) != 0) return 0;
      if ((x & 2) != 0) {
        return 1;
      }
      return 2;
    }
    k = 0;
    if ((x & 0xffff) == 0) {
      k = 16;
      x >>>= 16;
    }
    if ((x & 0xff) == 0) {
      k += 8;
      x >>>= 8;
    }
    if ((x & 0xf) == 0) {
      k += 4;
      x >>>= 4;
    }
    if ((x & 0x3) == 0) {
      k += 2;
      x >>>= 2;
    }
    if ((x & 1) == 0) {
      k++;
      x >>>= 1;
      if ((x & 1) == 0) return 32;
    }
    return k;
  }

  /* Return the number (0 through 32) of most significant zero bits in x. */
  private static int hi0bits(int x) {
    int k = 0;

    if ((x & 0xffff0000) == 0) {
      k = 16;
      x <<= 16;
    }
    if ((x & 0xff000000) == 0) {
      k += 8;
      x <<= 8;
    }
    if ((x & 0xf0000000) == 0) {
      k += 4;
      x <<= 4;
    }
    if ((x & 0xc0000000) == 0) {
      k += 2;
      x <<= 2;
    }
    if ((x & 0x80000000) == 0) {
      k++;
      if ((x & 0x40000000) == 0) return 32;
    }
    return k;
  }

  private static void stuffBits(byte bits[], int offset, int val) {
    bits[offset] = (byte) (val >> 24);
    bits[offset + 1] = (byte) (val >> 16);
    bits[offset + 2] = (byte) (val >> 8);
    bits[offset + 3] = (byte) (val);
  }

  /* Convert d into the form b*2^e, where b is an odd integer.  b is the returned
   * Bigint and e is the returned binary exponent.  Return the number of significant
   * bits in b in bits.  d must be finite and nonzero. */
  private static BigInteger d2b(double d, int[] e, int[] bits) {
    byte dbl_bits[];
    int i, k, y, z, de;
    long dBits = Double.doubleToLongBits(d);
    int d0 = (int) (dBits >>> 32);
    int d1 = (int) (dBits);

    z = d0 & Frac_mask;
    d0 &= 0x7fffffff; /* clear sign bit, which we ignore */

    if ((de = (d0 >>> Exp_shift)) != 0) z |= Exp_msk1;

    if ((y = d1) != 0) {
      dbl_bits = new byte[8];
      k = lo0bits(y);
      y >>>= k;
      if (k != 0) {
        stuffBits(dbl_bits, 4, y | z << (32 - k));
        z >>= k;
      } else stuffBits(dbl_bits, 4, y);
      stuffBits(dbl_bits, 0, z);
      i = (z != 0) ? 2 : 1;
    } else {
      //        JS_ASSERT(z);
      dbl_bits = new byte[4];
      k = lo0bits(z);
      z >>>= k;
      stuffBits(dbl_bits, 0, z);
      k += 32;
      i = 1;
    }
    if (de != 0) {
      e[0] = de - Bias - (P - 1) + k;
      bits[0] = P - k;
    } else {
      e[0] = de - Bias - (P - 1) + 1 + k;
      bits[0] = 32 * i - hi0bits(z);
    }
    return new BigInteger(dbl_bits);
  }



  /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
   *
   * Inspired by "How to Print Floating-Point Numbers Accurately" by
   * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
   *
   * Modifications:
   *  1. Rather than iterating, we use a simple numeric overestimate
   *     to determine k = floor(log10(d)).  We scale relevant
   *     quantities using O(log2(k)) rather than O(k) multiplications.
   *  2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
   *     try to generate digits strictly left to right.  Instead, we
   *     compute with fewer bits and propagate the carry if necessary
   *     when rounding the final digit up.  This is often faster.
   *  3. Under the assumption that input will be rounded nearest,
   *     mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
   *     That is, we allow equality in stopping tests when the
   *     round-nearest rule will give the same floating-point value
   *     as would satisfaction of the stopping test with strict
   *     inequality.
   *  4. We remove common factors of powers of 2 from relevant
   *     quantities.
   *  5. When converting floating-point integers less than 1e16,
   *     we use floating-point arithmetic rather than resorting
   *     to multiple-precision integers.
   *  6. When asked to produce fewer than 15 digits, we first try
   *     to get by with floating-point arithmetic; we resort to
   *     multiple-precision integer arithmetic only if we cannot
   *     guarantee that the floating-point calculation has given
   *     the correctly rounded result.  For k requested digits and
   *     "uniformly" distributed input, the probability is
   *     something like 10^(k-15) that we must resort to the Long
   *     calculation.
   */

  private static int word0(double d) {
    long dBits = Double.doubleToLongBits(d);
    return (int) (dBits >> 32);
  }

  private static double setWord0(double d, int i) {
    long dBits = Double.doubleToLongBits(d);
    dBits = ((long) i << 32) | (dBits & 0x0FFFFFFFFL);
    return Double.longBitsToDouble(dBits);
  }

  private static int word1(double d) {
    long dBits = Double.doubleToLongBits(d);
    return (int) (dBits);
  }

  /* Return b * 5^k.  k must be nonnegative. */
  // XXXX the C version built a cache of these
  private static BigInteger pow5mult(BigInteger b, int k) {
    return b.multiply(BigInteger.valueOf(5).pow(k));
  }

  private static boolean roundOff(StringBuilder buf) {
    int i = buf.length();
    while (i != 0) {
      --i;
      char c = buf.charAt(i);
      if (c != '9') {
        buf.setCharAt(i, (char) (c + 1));
        buf.setLength(i + 1);
        return false;
      }
    }
    buf.setLength(0);
    return true;
  }

  /* Always emits at least one digit. */
  /* If biasUp is set, then rounding in modes 2 and 3 will round away from zero
   * when the number is exactly halfway between two representable values.  For example,
   * rounding 2.5 to zero digits after the decimal point will return 3 and not 2.
   * 2.49 will still round to 2, and 2.51 will still round to 3. */
  /* bufsize should be at least 20 for modes 0 and 1.  For the other modes,
   * bufsize should be two greater than the maximum number of output characters expected. */
  @SuppressWarnings("BoxedPrimitiveEquality")
  private static int JS_dtoa(
      double d, int mode, boolean biasUp, int ndigits, boolean[] sign, StringBuilder buf) {
    /*  Arguments ndigits, decpt, sign are similar to those
        of ecvt and fcvt; trailing zeros are suppressed from
        the returned string.  If not null, *rve is set to point
        to the end of the return value.  If d is +-Infinity or NaN,
        then *decpt is set to 9999.

        mode:
        0 ==> shortest string that yields d when read in
        and rounded to nearest.
        1 ==> like 0, but with Steele & White stopping rule;
        e.g. with IEEE P754 arithmetic , mode 0 gives
        1e23 whereas mode 1 gives 9.999999999999999e22.
        2 ==> max(1,ndigits) significant digits.  This gives a
        return value similar to that of ecvt, except
        that trailing zeros are suppressed.
        3 ==> through ndigits past the decimal point.  This
        gives a return value similar to that from fcvt,
        except that trailing zeros are suppressed, and
        ndigits can be negative.
        4-9 should give the same return values as 2-3, i.e.,
        4 <= mode <= 9 ==> same return as mode
        2 + (mode & 1).  These modes are mainly for
        debugging; often they run slower but sometimes
        faster than modes 2-3.
        4,5,8,9 ==> left-to-right digit generation.
        6-9 ==> don't try fast floating-point estimate
        (if applicable).

        Values of mode other than 0-9 are treated as mode 0.

        Sufficient space is allocated to the return value
        to hold the suppressed trailing zeros.
    */

    int b2, b5, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, m2, m5, s2, s5;
    char dig;
    long L;
    long x;
    BigInteger b, b1, delta, mlo, mhi, S;
    int[] be = new int[1];
    int[] bbits = new int[1];
    double d2, ds, eps;
    boolean spec_case, denorm, k_check, try_quick, leftright;

    if ((word0(d) & Sign_bit) != 0) {
      /* set sign for everything, including 0's and NaNs */
      sign[0] = true;
      // word0(d) &= ~Sign_bit;  /* clear sign bit */
      d = setWord0(d, word0(d) & ~Sign_bit);
    } else sign[0] = false;

    if ((word0(d) & Exp_mask) == Exp_mask) {
      /* Infinity or NaN */
      buf.append(((word1(d) == 0) && ((word0(d) & Frac_mask) == 0)) ? "Infinity" : "NaN");
      return 9999;
    }
    if (d == 0) {
      //          no_digits:
      buf.setLength(0);
      buf.append('0'); /* copy "0" to buffer */
      return 1;
    }

    b = d2b(d, be, bbits);
    if ((i = (word0(d) >>> Exp_shift1 & (Exp_mask >> Exp_shift1))) != 0) {
      d2 = setWord0(d, (word0(d) & Frac_mask1) | Exp_11);
      /* log(x)   ~=~ log(1.5) + (x-1.5)/1.5
       * log10(x)  =  log(x) / log(10)
       *      ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
       * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
       *
       * This suggests computing an approximation k to log10(d) by
       *
       * k = (i - Bias)*0.301029995663981
       *  + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
       *
       * We want k to be too large rather than too small.
       * The error in the first-order Taylor series approximation
       * is in our favor, so we just round up the constant enough
       * to compensate for any error in the multiplication of
       * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
       * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
       * adding 1e-13 to the constant term more than suffices.
       * Hence we adjust the constant term to 0.1760912590558.
       * (We could get a more accurate k by invoking log10,
       *  but this is probably not worthwhile.)
       */
      i -= Bias;
      denorm = false;
    } else {
      /* d is denormalized */
      i = bbits[0] + be[0] + (Bias + (P - 1) - 1);
      x =
          (i > 32)
              ? ((long) word0(d)) << (64 - i) | word1(d) >>> (i - 32)
              : ((long) word1(d)) << (32 - i);
      //            d2 = x;
      //            word0(d2) -= 31*Exp_msk1; /* adjust exponent */
      d2 = setWord0(x, word0(x) - 31 * Exp_msk1);
      i -= (Bias + (P - 1) - 1) + 1;
      denorm = true;
    }
    /* At this point d = f*2^i, where 1 <= f < 2.  d2 is an approximation of f. */
    ds = (d2 - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
    k = (int) ds;
    if (ds < 0.0 && ds != k) k--; /* want k = floor(ds) */
    k_check = true;
    if (k >= 0 && k <= Ten_pmax) {
      if (d < tens[k]) k--;
      k_check = false;
    }
    /* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
    If k_check is zero, we're guaranteed that k = floor(log10(d)). */
    j = bbits[0] - i - 1;
    /* At this point d = b/2^j, where b is an odd integer. */
    if (j >= 0) {
      b2 = 0;
      s2 = j;
    } else {
      b2 = -j;
      s2 = 0;
    }
    if (k >= 0) {
      b5 = 0;
      s5 = k;
      s2 += k;
    } else {
      b2 -= k;
      b5 = -k;
      s5 = 0;
    }
    /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
    b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
    if (mode < 0 || mode > 9) mode = 0;
    try_quick = true;
    if (mode > 5) {
      mode -= 4;
      try_quick = false;
    }
    leftright = true;
    ilim = ilim1 = 0;
    switch (mode) {
      case 0:
      case 1:
        ilim = ilim1 = -1;
        i = 18;
        ndigits = 0;
        break;
      case 2:
        leftright = false;
        // fall through
      case 4:
        if (ndigits <= 0) ndigits = 1;
        ilim = ilim1 = i = ndigits;
        break;
      case 3:
        leftright = false;
        // fall through
      case 5:
        i = ndigits + k + 1;
        ilim = i;
        ilim1 = i - 1;
        if (i <= 0) i = 1;
    }
    /* ilim is the maximum number of significant digits we want, based on k and ndigits. */
    /* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
    when it turns out that k was computed too high by one. */

    boolean fast_failed = false;
    if (ilim >= 0 && ilim <= Quick_max && try_quick) {

      /* Try to get by with floating-point arithmetic. */

      i = 0;
      d2 = d;
      k0 = k;
      ilim0 = ilim;
      ieps = 2; /* conservative */
      /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
      if (k > 0) {
        ds = tens[k & 0xf];
        j = k >> 4;
        if ((j & Bletch) != 0) {
          /* prevent overflows */
          j &= Bletch - 1;
          d /= bigtens[n_bigtens - 1];
          ieps++;
        }
        for (; (j != 0); j >>= 1, i++)
          if ((j & 1) != 0) {
            ieps++;
            ds *= bigtens[i];
          }
        d /= ds;
      } else if ((j1 = -k) != 0) {
        d *= tens[j1 & 0xf];
        for (j = j1 >> 4; (j != 0); j >>= 1, i++)
          if ((j & 1) != 0) {
            ieps++;
            d *= bigtens[i];
          }
      }
      /* Check that k was computed correctly. */
      if (k_check && d < 1.0 && ilim > 0) {
        if (ilim1 <= 0) fast_failed = true;
        else {
          ilim = ilim1;
          k--;
          d *= 10.;
          ieps++;
        }
      }
      /* eps bounds the cumulative error. */
      //            eps = ieps*d + 7.0;
      //            word0(eps) -= (P-1)*Exp_msk1;
      eps = ieps * d + 7.0;
      eps = setWord0(eps, word0(eps) - (P - 1) * Exp_msk1);
      if (ilim == 0) {
        S = mhi = null;
        d -= 5.0;
        if (d > eps) {
          buf.append('1');
          k++;
          return k + 1;
        }
        if (d < -eps) {
          buf.setLength(0);
          buf.append('0'); /* copy "0" to buffer */
          return 1;
        }
        fast_failed = true;
      }
      if (!fast_failed) {
        fast_failed = true;
        if (leftright) {
          /* Use Steele & White method of only
           * generating digits needed.
           */
          eps = 0.5 / tens[ilim - 1] - eps;
          for (i = 0; ; ) {
            L = (long) d;
            d -= L;
            buf.append((char) ('0' + L));
            if (d < eps) {
              return k + 1;
            }
            if (1.0 - d < eps) {
              //                            goto bump_up;
              char lastCh;
              while (true) {
                lastCh = buf.charAt(buf.length() - 1);
                buf.setLength(buf.length() - 1);
                if (lastCh != '9') break;
                if (buf.length() == 0) {
                  k++;
                  lastCh = '0';
                  break;
                }
              }
              buf.append((char) (lastCh + 1));
              return k + 1;
            }
            if (++i >= ilim) break;
            eps *= 10.0;
            d *= 10.0;
          }
        } else {
          /* Generate ilim digits, then fix them up. */
          eps *= tens[ilim - 1];
          for (i = 1; ; i++, d *= 10.0) {
            L = (long) d;
            d -= L;
            buf.append((char) ('0' + L));
            if (i == ilim) {
              if (d > 0.5 + eps) {
                //                                goto bump_up;
                char lastCh;
                while (true) {
                  lastCh = buf.charAt(buf.length() - 1);
                  buf.setLength(buf.length() - 1);
                  if (lastCh != '9') break;
                  if (buf.length() == 0) {
                    k++;
                    lastCh = '0';
                    break;
                  }
                }
                buf.append((char) (lastCh + 1));
                return k + 1;
              } else if (d < 0.5 - eps) {
                stripTrailingZeroes(buf);
                //                                    while(*--s == '0') ;
                //                                    s++;
                return k + 1;
              }
              break;
            }
          }
        }
      }
      if (fast_failed) {
        buf.setLength(0);
        d = d2;
        k = k0;
        ilim = ilim0;
      }
    }

    /* Do we have a "small" integer? */

    if (be[0] >= 0 && k <= Int_max) {
      /* Yes. */
      ds = tens[k];
      if (ndigits < 0 && ilim <= 0) {
        S = mhi = null;
        if (ilim < 0 || d < 5 * ds || (!biasUp && d == 5 * ds)) {
          buf.setLength(0);
          buf.append('0'); /* copy "0" to buffer */
          return 1;
        }
        buf.append('1');
        k++;
        return k + 1;
      }
      for (i = 1; ; i++) {
        L = (long) (d / ds);
        d -= L * ds;
        buf.append((char) ('0' + L));
        if (i == ilim) {
          d += d;
          if ((d > ds) || (d == ds && (((L & 1) != 0) || biasUp))) {
            //                    bump_up:
            //                        while(*--s == '9')
            //                            if (s == buf) {
            //                                k++;
            //                                *s = '0';
            //                                break;
            //                            }
            //                        ++*s++;
            char lastCh;
            while (true) {
              lastCh = buf.charAt(buf.length() - 1);
              buf.setLength(buf.length() - 1);
              if (lastCh != '9') break;
              if (buf.length() == 0) {
                k++;
                lastCh = '0';
                break;
              }
            }
            buf.append((char) (lastCh + 1));
          }
          break;
        }
        d *= 10.0;
        if (d == 0) break;
      }
      return k + 1;
    }

    m2 = b2;
    m5 = b5;
    mhi = mlo = null;
    if (leftright) {
      if (mode < 2) {
        i = (denorm) ? be[0] + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits[0];
        /* i is 1 plus the number of trailing zero bits in d's significand. Thus,
        (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
      } else {
        j = ilim - 1;
        if (m5 >= j) m5 -= j;
        else {
          s5 += j -= m5;
          b5 += j;
          m5 = 0;
        }
        if ((i = ilim) < 0) {
          m2 -= i;
          i = 0;
        }
        /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
      }
      b2 += i;
      s2 += i;
      mhi = BigInteger.valueOf(1);
      /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
      input (when mode < 2) significant digit, divided by 10^k. */
    }
    /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5).  Reduce common factors in
    b2, m2, and s2 without changing the equalities. */
    if (m2 > 0 && s2 > 0) {
      i = (m2 < s2) ? m2 : s2;
      b2 -= i;
      m2 -= i;
      s2 -= i;
    }

    /* Fold b5 into b and m5 into mhi. */
    if (b5 > 0) {
      if (leftright) {
        if (m5 > 0) {
          mhi = pow5mult(mhi, m5);
          b1 = mhi.multiply(b);
          b = b1;
        }
        if ((j = b5 - m5) != 0) b = pow5mult(b, j);
      } else b = pow5mult(b, b5);
    }
    /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
    (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */

    S = BigInteger.valueOf(1);
    if (s5 > 0) S = pow5mult(S, s5);
    /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
    (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */

    /* Check for special case that d is a normalized power of 2. */
    spec_case = false;
    if (mode < 2) {
      if ((word1(d) == 0)
          && ((word0(d) & Bndry_mask) == 0)
          && ((word0(d) & (Exp_mask & Exp_mask << 1)) != 0)) {
        /* The special case.  Here we want to be within a quarter of the last input
        significant digit instead of one half of it when the decimal output string's value is less than d.  */
        b2 += Log2P;
        s2 += Log2P;
        spec_case = true;
      }
    }

    /* Arrange for convenient computation of quotients:
     * shift left if necessary so divisor has 4 leading 0 bits.
     *
     * Perhaps we should just compute leading 28 bits of S once
     * and for all and pass them and a shift to quorem, so it
     * can do shifts and ors to compute the numerator for q.
     */
    byte[] S_bytes = S.toByteArray();
    int S_hiWord = 0;
    for (int idx = 0; idx < 4; idx++) {
      S_hiWord = (S_hiWord << 8);
      if (idx < S_bytes.length) S_hiWord |= (S_bytes[idx] & 0xFF);
    }
    if ((i = (((s5 != 0) ? 32 - hi0bits(S_hiWord) : 1) + s2) & 0x1f) != 0) i = 32 - i;
    /* i is the number of leading zero bits in the most significant word of S*2^s2. */
    if (i > 4) {
      i -= 4;
      b2 += i;
      m2 += i;
      s2 += i;
    } else if (i < 4) {
      i += 28;
      b2 += i;
      m2 += i;
      s2 += i;
    }
    /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
    if (b2 > 0) b = b.shiftLeft(b2);
    if (s2 > 0) S = S.shiftLeft(s2);
    /* Now we have d/10^k = b/S and
    (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
    if (k_check) {
      if (b.compareTo(S) < 0) {
        k--;
        b = b.multiply(BigInteger.valueOf(10)); /* we botched the k estimate */
        if (leftright) mhi = mhi.multiply(BigInteger.valueOf(10));
        ilim = ilim1;
      }
    }
    /* At this point 1 <= d/10^k = b/S < 10. */

    if (ilim <= 0 && mode > 2) {
      /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
      Output either zero or the minimum nonzero output depending on which is closer to d. */
      if ((ilim < 0)
          || ((i = b.compareTo(S = S.multiply(BigInteger.valueOf(5)))) < 0)
          || ((i == 0 && !biasUp))) {
        /* Always emit at least one digit.  If the number appears to be zero
        using the current mode, then emit one '0' digit and set decpt to 1. */
        /*no_digits:
        k = -1 - ndigits;
        goto ret; */
        buf.setLength(0);
        buf.append('0'); /* copy "0" to buffer */
        return 1;
        //                goto no_digits;
      }
      //        one_digit:
      buf.append('1');
      k++;
      return k + 1;
    }
    if (leftright) {
      if (m2 > 0) mhi = mhi.shiftLeft(m2);

      /* Compute mlo -- check for special case
       * that d is a normalized power of 2.
       */

      mlo = mhi;
      if (spec_case) {
        mhi = mlo;
        mhi = mhi.shiftLeft(Log2P);
      }
      /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
      /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */

      for (i = 1; ; i++) {
        BigInteger[] divResult = b.divideAndRemainder(S);
        b = divResult[1];
        dig = (char) (divResult[0].intValue() + '0');
        /* Do we yet have the shortest decimal string
         * that will round to d?
         */
        j = b.compareTo(mlo);
        /* j is b/S compared with mlo/S. */
        delta = S.subtract(mhi);
        j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta);
        /* j1 is b/S compared with 1 - mhi/S. */
        if ((j1 == 0) && (mode == 0) && ((word1(d) & 1) == 0)) {
          if (dig == '9') {
            buf.append('9');
            if (roundOff(buf)) {
              k++;
              buf.append('1');
            }
            return k + 1;
            //                        goto round_9_up;
          }
          if (j > 0) dig++;
          buf.append(dig);
          return k + 1;
        }
        if ((j < 0) || ((j == 0) && (mode == 0) && ((word1(d) & 1) == 0))) {
          if (j1 > 0) {
            /* Either dig or dig+1 would work here as the least significant decimal digit.
            Use whichever would produce a decimal value closer to d. */
            b = b.shiftLeft(1);
            j1 = b.compareTo(S);
            if (((j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp))) && (dig++ == '9')) {
              buf.append('9');
              if (roundOff(buf)) {
                k++;
                buf.append('1');
              }
              return k + 1;
              //                                goto round_9_up;
            }
          }
          buf.append(dig);
          return k + 1;
        }
        if (j1 > 0) {
          if (dig == '9') {
            /* possible if i == 1 */
            //                    round_9_up:
            //                        *s++ = '9';
            //                        goto roundoff;
            buf.append('9');
            if (roundOff(buf)) {
              k++;
              buf.append('1');
            }
            return k + 1;
          }
          buf.append((char) (dig + 1));
          return k + 1;
        }
        buf.append(dig);
        if (i == ilim) break;
        b = b.multiply(BigInteger.valueOf(10));
        if (mlo == mhi) mlo = mhi = mhi.multiply(BigInteger.valueOf(10));
        else {
          mlo = mlo.multiply(BigInteger.valueOf(10));
          mhi = mhi.multiply(BigInteger.valueOf(10));
        }
      }
    } else
      for (i = 1; ; i++) {
        //                (char)(dig = quorem(b,S) + '0');
        BigInteger[] divResult = b.divideAndRemainder(S);
        b = divResult[1];
        dig = (char) (divResult[0].intValue() + '0');
        buf.append(dig);
        if (i >= ilim) break;
        b = b.multiply(BigInteger.valueOf(10));
      }

    /* Round off last digit */

    b = b.shiftLeft(1);
    j = b.compareTo(S);
    if ((j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp))) {
      //        roundoff:
      //            while(*--s == '9')
      //                if (s == buf) {
      //                    k++;
      //                    *s++ = '1';
      //                    goto ret;
      //                }
      //            ++*s++;
      if (roundOff(buf)) {
        k++;
        buf.append('1');
        return k + 1;
      }
    } else {
      stripTrailingZeroes(buf);
      //            while(*--s == '0') ;
      //            s++;
    }
    //      ret:
    //        Bfree(S);
    //        if (mhi) {
    //            if (mlo && mlo != mhi)
    //                Bfree(mlo);
    //            Bfree(mhi);
    //        }
    //      ret1:
    //        Bfree(b);
    //        JS_ASSERT(s < buf + bufsize);
    return k + 1;
  }

  private static void stripTrailingZeroes(StringBuilder buf) {
    //      while(*--s == '0') ;
    //      s++;
    int bl = buf.length();
    while (bl-- > 0 && buf.charAt(bl) == '0') {
      // empty
    }
    buf.setLength(bl + 1);
  }

  /* Mapping of JSDToStrMode -> JS_dtoa mode */
  private static final int dtoaModes[] = {
    0, /* DTOSTR_STANDARD */ 0, /* DTOSTR_STANDARD_EXPONENTIAL, */ 3, /* DTOSTR_FIXED, */
    2, /* DTOSTR_EXPONENTIAL, */ 2
  }; /* DTOSTR_PRECISION */

  private static void JS_dtostr(StringBuilder buffer, int mode, int precision, double d) {
    int decPt; /* Position of decimal point relative to first digit returned by JS_dtoa */
    boolean[] sign = new boolean[1]; /* true if the sign bit was set in d */
    int nDigits; /* Number of significand digits returned by JS_dtoa */

    //        JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE :
    //                DTOSTR_VARIABLE_BUFFER_SIZE(precision)));

    if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21))
      mode =
          DTOSTR_STANDARD; /* Change mode here rather than below because the buffer may not be large enough to hold a large integer. */

    decPt = JS_dtoa(d, dtoaModes[mode], mode >= DTOSTR_FIXED, precision, sign, buffer);
    nDigits = buffer.length();

    /* If Infinity, -Infinity, or NaN, return the string regardless of the mode. */
    if (decPt != 9999) {
      boolean exponentialNotation = false;
      int minNDigits = 0; /* Minimum number of significand digits required by mode and precision */
      int p;

      switch (mode) {
        case DTOSTR_STANDARD:
          if (decPt < -5 || decPt > 21) exponentialNotation = true;
          else minNDigits = decPt;
          break;

        case DTOSTR_FIXED:
          if (precision >= 0) minNDigits = decPt + precision;
          else minNDigits = decPt;
          break;

        case DTOSTR_EXPONENTIAL:
          //                    JS_ASSERT(precision > 0);
          minNDigits = precision;
          /* Fall through */
        case DTOSTR_STANDARD_EXPONENTIAL:
          exponentialNotation = true;
          break;

        case DTOSTR_PRECISION:
          //                    JS_ASSERT(precision > 0);
          minNDigits = precision;
          if (decPt < -5 || decPt > precision) exponentialNotation = true;
          break;
      }

      /* If the number has fewer than minNDigits, pad it with zeros at the end */
      if (nDigits < minNDigits) {
        p = minNDigits;
        nDigits = minNDigits;
        do {
          buffer.append('0');
        } while (buffer.length() != p);
      }

      if (exponentialNotation) {
        /* Insert a decimal point if more than one significand digit */
        if (nDigits != 1) {
          buffer.insert(1, '.');
        }
        buffer.append('e');
        if ((decPt - 1) >= 0) buffer.append('+');
        buffer.append(decPt - 1);
        //                JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1);
      } else if (decPt != nDigits) {
        /* Some kind of a fraction in fixed notation */
        //                JS_ASSERT(decPt <= nDigits);
        if (decPt > 0) {
          /* dd...dd . dd...dd */
          buffer.insert(decPt, '.');
        } else {
          /* 0 . 00...00dd...dd */
          for (int i = 0; i < 1 - decPt; i++) buffer.insert(0, '0');
          buffer.insert(1, '.');
        }
      }
    }

    /* If negative and neither -0.0 nor NaN, output a leading '-'. */
    if (sign[0]
        && !(word0(d) == Sign_bit && word1(d) == 0)
        && !((word0(d) & Exp_mask) == Exp_mask
            && ((word1(d) != 0) || ((word0(d) & Frac_mask) != 0)))) {
      buffer.insert(0, '-');
    }
  }

  public static String numberToString(double value) {
    if (Double.isNaN(value)) return "NaN";
    if (value == 0.0) return "0";
    if (value < 0) return "-" + numberToString(-value);
    if (Double.isInfinite(value)) return "Infinity";

    StringBuilder buffer = new StringBuilder();
    DToA.JS_dtostr(buffer, DToA.DTOSTR_STANDARD, 0, value);
    return buffer.toString();
  }

  private DToA() {}
}
